package com.guangjian.common.sql;

import java.util.HashMap;

import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import com.sun.org.apache.regexp.internal.RE;
import com.sun.org.apache.regexp.internal.RESyntaxException;

public class SqlXMLHandler extends DefaultHandler {
	private static Logger log = Logger.getLogger(SqlXMLHandler.class);

	private final int OPENED = 1;

	private final int CLOSED = 2;

	private final String LIST_TAG_NAME = "sqlList";

	private final String SQL_TAG_NAME = "sql";

	private final String ATTR_NAME = "sqlId";
	private boolean listOpened;
	private int state = 2;
	private String sqlId;
	private String sql;
	
	private HashMap<String, String> map;
	private boolean commentFlag = false;

	public SqlXMLHandler(HashMap<String, String> map) {
		this.map = map;
	}

	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if (localName.equals("sqlList")) {
			this.listOpened = true;
		} else {
			if ((localName.equals("sql")) && (!(this.listOpened))) {
				throw new SAXException("<sqlList> not exists!");
			}

			String tempId = attributes.getValue("sqlId");

			if (this.state == 1) {
				throw new SAXException("sqlId='" + this.sqlId + "' has not any end tag!");
			}

			if (tempId == null) {
				if (this.sqlId == null) {
					throw new SAXException("The sqlId attribute of the element is not valid!");
				}
				throw new SAXException("sqlId='" + this.sqlId + "' is not valid!");
			}

			this.sqlId = tempId;
			this.sql = "";
			this.state = 1;
		}
	}

	public void endElement(String uri, String localName, String qName) throws SAXException {
		try {
			if ((!(localName.equals("sql"))) || (this.state != 1))
				return;
			this.sql += "\n";
			RE r = null;

			int fromIndex = 0;
			int flag = this.sql.indexOf("/*", fromIndex);
			while (flag > -1) {
				if (this.sql.indexOf("/*+", fromIndex) != flag)
					this.sql = this.sql.substring(0, flag) + this.sql.substring(this.sql.indexOf("*/", fromIndex) + 2);
				else {
					fromIndex = this.sql.indexOf("*/", fromIndex) + 2;
				}
				flag = this.sql.indexOf("/*", fromIndex);
			}

			this.sql = removeComment(this.sql);

			r = new RE("[\n]");
			if (r.match(this.sql)) {
				this.sql = r.subst(this.sql, " ");
			}

			r = new RE("[\t]+");
			if (r.match(this.sql)) {
				this.sql = r.subst(this.sql, " ");
			}

			this.sql = this.sql.trim();

			this.map.put(this.sqlId, this.sql);
			this.state = 2;
		} catch (RESyntaxException e) {
			log.info(e.getMessage());
			throw e;
		}
	}

	public void characters(char[] ch, int offset, int length) throws SAXException {
		String str = "";
		String tempStr = "";
		if (this.state == 1) {
			str = new String(ch, offset, length);

			tempStr = " " + str.trim() + " ";

			if ((tempStr == null) || (tempStr.equals(""))) {
				if (!(this.commentFlag)) {
					this.sql += str;
				}

				return;
			}

			if (this.commentFlag) {
				str = tempStr;
			}

			if (str.indexOf("/*") >= 0) {
				this.commentFlag = true;
			}

			if (str.indexOf("*/") >= 0) {
				this.commentFlag = false;
			}

			this.sql += str;
		}
	}

	public void fatalError(SAXParseException e) throws SAXException {
		String message = "";

		if ((this.state == 2) && (this.sqlId == null))
			throw new SAXException("Start tag is the first element has been closed");
		if (this.state == 2) {
			throw new SAXException("sqlId='" + this.sqlId + "' Did you start with the element tag closed、</" + "sqlList" + "> tag is not exists!");
		}
		throw new SAXException(message);
	}

	private static String removeComment(String str) {
		String[] sqls = str.split("\n");
		String sql = "";
		for (int i = 0; i < sqls.length; ++i) {
			String sqlTemp = sqls[i] + "\n";
			int fromIndex = 0;
			int beg = sqlTemp.indexOf("--", fromIndex);
			while (beg >= fromIndex) {
				String sqlSub = sqlTemp.substring(0, beg);

				if (isQuoteString(sqlSub)) {
					fromIndex = beg + 2;
				} else {
					sqlTemp = sqlTemp.substring(0, beg) + "\n";
					break;
				}
				beg = sqlTemp.indexOf("--", fromIndex);
			}
			sql = sql + sqlTemp;
		}

		return sql;
	}

	private static boolean isQuoteString(String str) {
		int num = 0;
		char sep = '\'';
		char[] subSql = str.toCharArray();
		for (char sepTemp : subSql) {
			if (sep == sepTemp) {
				++num;
			}

		}

		return (num % 2 == 1);
	}
}